/*
 * ESPRESSIF MIT License
 *
 * Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
 *
 * Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case,
 * it is free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
 * to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

#ifndef __PCM5121_H__
#define __PCM5121_H__

#include "esp_types.h"
#include "audio_hal.h"
#include "driver/i2c.h"
#include "pcmxxxx_common.h"

#ifdef __cplusplus
extern "C" {
#endif

/* PCM5121 address */
#define PCM5121_ADDR 0x98  /*!< 0x98:ADR2=0,ADR1=0*/

/*
    PCM5121 page select register 

    In any page, register 0 is the Page Select Register. The register value selects the Register Page from 0 to 255
    for next read or write command.
*/
#define PCM5121_PAGE_SET_REG     0x00   

/* 
    PCM5121 register page0 

    Desc:General Control and Configuration
*/
#define PCM5121_PAGE0_01         0x01   /* Analog control register */
#define PCM5121_PAGE0_02         0x02   /* Standby, Powerdown requests */
#define PCM5121_PAGE0_03         0x03   /* Mute */
#define PCM5121_PAGE0_04         0x04   /* PLL Lock Flag, PLL enable */
#define PCM5121_PAGE0_05         0x05   /* Reserved */
#define PCM5121_PAGE0_06         0x06   /* SPI MISO function select */
#define PCM5121_PAGE0_07         0x07   /* De-emphasis enable, SDOUT select */
#define PCM5121_PAGE0_08         0x08   /* GPIO enables */
#define PCM5121_PAGE0_09         0x09   /* BCK, LRCLK configuration */
#define PCM5121_PAGE0_0A         0x0A   /* DSP GPIO Input */

#define PCM5121_PAGE0_0B         0x0B   /* Reserved */
#define PCM5121_PAGE0_0C         0x0C   /* Master mode BCK, LRCLK reset */
#define PCM5121_PAGE0_0D         0x0D   /* PLL clock source select */
#define PCM5121_PAGE0_0E         0x0E   /* Reserved */
#define PCM5121_PAGE0_0F         0x0F   /* Reserved */
#define PCM5121_PAGE0_10         0x10   /* Reserved */
#define PCM5121_PAGE0_11         0x11   /* Reserved */
#define PCM5121_PAGE0_12         0x12   /* Reserved */
#define PCM5121_PAGE0_13         0x13   /* Reserved */
#define PCM5121_PAGE0_14         0x14   /* PLL dividers */

#define PCM5121_PAGE0_15         0x15   /* PLL dividers */
#define PCM5121_PAGE0_16         0x16   /* PLL dividers */
#define PCM5121_PAGE0_17         0x17   /* PLL dividers */
#define PCM5121_PAGE0_18         0x18   /* PLL dividers */
#define PCM5121_PAGE0_19         0x19   /* Reserved */
#define PCM5121_PAGE0_1A         0x1A   /* Reserved */
#define PCM5121_PAGE0_1B         0x1B   /* DSP clock divider */
#define PCM5121_PAGE0_1C         0x1C   /* DAC clock divider */
#define PCM5121_PAGE0_1D         0x1D   /* NCP clock divider */
#define PCM5121_PAGE0_1E         0x1E   /* OSR clock divider */

#define PCM5121_PAGE0_1F         0x1F   /* Reserved */
#define PCM5121_PAGE0_20         0x20   /* Master mode dividers */
#define PCM5121_PAGE0_21         0x21   /* Master mode dividers */
#define PCM5121_PAGE0_22         0x22   /* fS speed mode */
#define PCM5121_PAGE0_23         0x23   /* IDAC (number of DSP clock cycles available inone audio frame) */
#define PCM5121_PAGE0_24         0x24   /* IDAC (number of DSP clock cycles available inone audio frame) */
#define PCM5121_PAGE0_25         0x25   /* gnore various errors */
#define PCM5121_PAGE0_26         0x26   /* Reserved */
#define PCM5121_PAGE0_27         0x27   /* Reserved */
#define PCM5121_PAGE0_28         0x28   /* I2S configuration */

#define PCM5121_PAGE0_29         0x29   /* I2S configuration */
#define PCM5121_PAGE0_2A         0x2A   /* DAC data path */
#define PCM5121_PAGE0_2B         0x2B   /* DSP program selection */
#define PCM5121_PAGE0_2C         0x2C   /* Clock missing detection period */
#define PCM5121_PAGE0_2D         0x2D   /*  */
#define PCM5121_PAGE0_2E         0x2E   /*  */
#define PCM5121_PAGE0_2F         0x2F   /*  */
#define PCM5121_PAGE0_30         0x30   /*  */
#define PCM5121_PAGE0_31         0x31   /*  */
#define PCM5121_PAGE0_32         0x32   /*  */

#define PCM5121_PAGE0_33         0x33   /*  */
#define PCM5121_PAGE0_34         0x34   /*  */
#define PCM5121_PAGE0_35         0x35   /*  */
#define PCM5121_PAGE0_36         0x36   /*  */
#define PCM5121_PAGE0_37         0x37   /*  */
#define PCM5121_PAGE0_38         0x38   /*  */
#define PCM5121_PAGE0_39         0x39   /*  */
#define PCM5121_PAGE0_3A         0x3A   /*  */
#define PCM5121_PAGE0_3B         0x3B   /* Auto mute time */
#define PCM5121_PAGE0_3C         0x3C   /* Digital volume */

#define PCM5121_PAGE0_3D         0x3D   /* Digital volume */
#define PCM5121_PAGE0_3E         0x3E   /* Digital volume */
#define PCM5121_PAGE0_3F         0x3F   /* Digital volume */
#define PCM5121_PAGE0_40         0x40   /* Digital volume */
#define PCM5121_PAGE0_41         0x41   /* Auto mute */
#define PCM5121_PAGE0_42         0x42   /* Reserved */
#define PCM5121_PAGE0_43         0x43   /* Reserved */
#define PCM5121_PAGE0_44         0x44   /* Reserved */
#define PCM5121_PAGE0_45         0x45   /* GPIOn output selection */
#define PCM5121_PAGE0_46         0x46   /* GPIOn output selection */

#define PCM5121_PAGE0_47         0x47   /* GPIOn output selection */
#define PCM5121_PAGE0_48         0x48   /* GPIOn output selection */
#define PCM5121_PAGE0_49         0x49   /* GPIOn output selection */
#define PCM5121_PAGE0_4A         0x4A   /* GPIOn output selection */
#define PCM5121_PAGE0_4B         0x4B   /* GPIO control */
#define PCM5121_PAGE0_4C         0x4C   /* GPIO control */
#define PCM5121_PAGE0_4D         0x4D   /* Reserved */
#define PCM5121_PAGE0_4E         0x4E   /* Reserved */
#define PCM5121_PAGE0_4F         0x4F   /* DSP overflow */
#define PCM5121_PAGE0_50         0x50   /* Sample rate statu */

#define PCM5121_PAGE0_51         0x51   /* Sample rate statu */
#define PCM5121_PAGE0_52         0x52   /* Sample rate statu */
#define PCM5121_PAGE0_53         0x53   /* Sample rate statu */
#define PCM5121_PAGE0_54         0x54   /* Reserved */
#define PCM5121_PAGE0_55         0x55   /* Reserved */
#define PCM5121_PAGE0_56         0x56   /* Reserved */
#define PCM5121_PAGE0_57         0x57   /* Reserved */
#define PCM5121_PAGE0_58         0x58   /* Reserved */
#define PCM5121_PAGE0_59         0x59   /* Reserved */
#define PCM5121_PAGE0_5A         0x5A   /* Reserved */

#define PCM5121_PAGE0_5B         0x5B   /* Reserved */
#define PCM5121_PAGE0_5C         0x5C   /* Reserved */
#define PCM5121_PAGE0_5D         0x5D   /* Reserved */
#define PCM5121_PAGE0_5E         0x5E   /* Reserved */
#define PCM5121_PAGE0_5F         0x5F   /* Reserved */
#define PCM5121_PAGE0_60         0x60   /* Reserved */
#define PCM5121_PAGE0_61         0x61   /* Analog mute monitor */
#define PCM5121_PAGE0_62         0x62   /* Reserved */
#define PCM5121_PAGE0_63         0x63   /* Reserved */
#define PCM5121_PAGE0_64         0x64   /* Reserved */

#define PCM5121_PAGE0_65         0x65   /* Reserved */
#define PCM5121_PAGE0_66         0x66   /* Reserved */
#define PCM5121_PAGE0_67         0x67   /* Reserved */
#define PCM5121_PAGE0_68         0x68   /* Reserved */
#define PCM5121_PAGE0_69         0x69   /* Reserved */
#define PCM5121_PAGE0_6A         0x6A   /* Reserved */
#define PCM5121_PAGE0_6B         0x6B   /* Reserved */
#define PCM5121_PAGE0_6C         0x6C   /* Analog mute monitor */
#define PCM5121_PAGE0_6D         0x6D   /* Reserved */
#define PCM5121_PAGE0_6E         0x6E   /* Reserved */

#define PCM5121_PAGE0_6F         0x6F   /* Reserved */
#define PCM5121_PAGE0_70         0x70   /* Reserved */
#define PCM5121_PAGE0_71         0x71   /* Reserved */
#define PCM5121_PAGE0_72         0x72   /* Reserved */
#define PCM5121_PAGE0_73         0x73   /* Reserved */
#define PCM5121_PAGE0_74         0x74   /* Reserved */
#define PCM5121_PAGE0_75         0x75   /* Reserved */
#define PCM5121_PAGE0_76         0x76   /* Reserved */
#define PCM5121_PAGE0_77         0x77   /* GPIO input */
#define PCM5121_PAGE0_78         0x78   /* Auto Mute flags */

#define PCM5121_PAGE0_79         0x79   /* Reserved */
#define PCM5121_PAGE0_7A         0x7A   /*  */
#define PCM5121_PAGE0_7B         0x7B   /*  */
#define PCM5121_PAGE0_7C         0x7C   /*  */
#define PCM5121_PAGE0_7D         0x7D   /*  */

/* 
    PCM5121 register page1 

    Desc:Analog Control
*/
#define PCM5121_PAGE1_01         0x01   /* Output amplitude type */
#define PCM5121_PAGE1_02         0x02   /* Analog gain control */
#define PCM5121_PAGE1_05         0x05   /* Undervoltage protection */
#define PCM5121_PAGE1_06         0x06   /* Analog mute control */
#define PCM5121_PAGE1_07         0x07   /* Analog gain boost */
#define PCM5121_PAGE1_08         0x08   /* VCOM configuration */
#define PCM5121_PAGE1_09         0x09   /* VCOM configuration */

/* PCM5121 register page44 */
#define PCM5121_PAGE44_01        0x01   /* Coefficient memory (CRAM) control */

/* PCM5121 register page253 */
#define PCM5121_PAGE253_3F       0x3F   /* Clock Flex Mode */
#define PCM5121_PAGE253_40       0x40   /* Clock Flex Mode */

/**
 * @brief Initialize PCM5121 codec chip
 *
 * @param cfg configuration of PCM5121
 *
 * @return
 *     - ESP_OK
 *     - ESP_FAIL
 */
esp_err_t pcm5121_init(audio_hal_codec_config_t *cfg);

/**
 * @brief Deinitialize PCM5121 codec chip
 *
 * @return
 *     - ESP_OK
 *     - ESP_FAIL
 */
esp_err_t pcm5121_deinit(void);

/**
 * @brief Configure PCM5121 I2S format
 *
 * @param mod:  set ADC or DAC or both
 * @param cfg:   PCM5121 I2S format
 *
 * @return
 *     - ESP_OK
 *     - ESP_FAIL
 */
esp_err_t pcm5121_config_fmt(pcm_module_t mod, audio_hal_iface_format_t fmt);

/**
 * @brief Configure PCM5121 data sample bits
 *
 * @param mode:  set ADC or DAC or both
 * @param bit_per_sample:  bit number of per sample
 *
 * @return
 *     - ESP_OK
 *     - ESP_FAIL
 */
esp_err_t pcm5121_set_bits_per_sample(pcm_module_t mode, pcm_bits_length_t bit_per_sample);

/**
 * @brief  Start PCM5121 codec chip
 *
 * @param mode:  set ADC or DAC or both
 *
 * @return
 *     - ESP_OK
 *     - ESP_FAIL
 */
esp_err_t pcm5121_start(pcm_module_t mode);

/**
 * @brief  Stop PCM5121 codec chip
 *
 * @param mode:  set ADC or DAC or both
 *
 * @return
 *     - ESP_OK
 *     - ESP_FAIL
 */
esp_err_t pcm5121_stop(pcm_module_t mode);

/**
 * @brief  Set voice volume
 *
 * @param volume:  voice volume (0~100)
 *
 * @return
 *     - ESP_OK
 *     - ESP_FAIL
 */
esp_err_t pcm5121_set_voice_volume(int volume);

/**
 * @brief Get voice volume
 *
 * @param[out] *volume:  voice volume (0~100)
 *
 * @return
 *     - ESP_OK
 *     - ESP_FAIL
 */
esp_err_t pcm5121_get_voice_volume(int *volume);

/**
 * @brief Configure PCM5121 DAC mute or not. Basically you can use this function to mute the output or unmute
 *
 * @param enable enable(1) or disable(0)
 *
 * @return
 *     - ESP_FAIL Parameter error
 *     - ESP_OK   Success
 */
esp_err_t pcm5121_set_voice_mute(bool enable);

/**
 * @brief Get PCM5121 DAC mute status
 *
 *  @return
 *     - ESP_FAIL Parameter error
 *     - ESP_OK   Success
 */
esp_err_t pcm5121_get_voice_mute(void);

/**
 * @brief Write PCM5121 register
 *
 * @param reg_add address of register
 * @param data data of register
 *
 * @return
 *     - ESP_FAIL Parameter error
 *     - ESP_OK   Success
 */
esp_err_t pcm5121_write_reg(uint8_t reg_add, uint8_t data);

/**
 * @brief Print all PCM5121 registers
 *
 * @return
 *     - void
 */
void pcm5121_read_all();

/**
 * @brief Configure PCM5121 codec mode and I2S interface
 *
 * @param mode codec mode
 * @param iface I2S config
 *
 * @return
 *     - ESP_FAIL Parameter error
 *     - ESP_OK   Success
 */
esp_err_t pcm5121_config_i2s(audio_hal_codec_mode_t mode, audio_hal_codec_i2s_iface_t *iface);

/**
 * @brief Control PCM5121 codec chip
 *
 * @param mode codec mode
 * @param ctrl_state start or stop decode or encode progress
 *
 * @return
 *     - ESP_FAIL Parameter error
 *     - ESP_OK   Success
 */
esp_err_t pcm5121_ctrl_state(audio_hal_codec_mode_t mode, audio_hal_ctrl_t ctrl_state);

/**
 * @brief Set PCM5121 PA power
 *
 * @param enable true for enable PA power, false for disable PA power
 *
 * @return
 *      - void
 */
void pcm5121_pa_power(bool enable);

#ifdef __cplusplus
}
#endif

#endif //__PCM5121_H__
